﻿using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;

namespace Blob_Watcher
{
    public class Gatekeeper
    {
        private CloudBlockBlob gateBlob;
        private AccessCondition gatekeeperAccess = null;
        private System.Timers.Timer leaseTimer = new System.Timers.Timer();

        public Gatekeeper(CloudBlockBlob mygatekeeper, string initialval)
        {
            this.gateBlob = mygatekeeper;

            // ensure my gatekeeper has been intialized
            if (!string.IsNullOrEmpty(initialval))
            {
                try
                {
                    this.GetText(); // try to download gatekeeper
                }
                catch (StorageException ex)
                {
                    if (ex.Message.Contains("(404) Not Found"))
                        this.SetText(initialval);// create object
                    else
                        throw ex;
                }
            }

            // configure the lease renewal event
            leaseTimer.Elapsed += RenewLeaseEvent;
            leaseTimer.Interval = new TimeSpan(0, 0, 45).TotalMilliseconds; // renew lease every 45 seconds
        }

        public bool Start()
        {
            try
            {
                if (this.gatekeeperAccess == null)
                {
                    string leaseid = gateBlob.AcquireLease(new TimeSpan(0, 1, 0), null); // lease for maximum of 1 minute
                    this.gatekeeperAccess = new AccessCondition()
                    {
                        LeaseId = leaseid
                    };

                    leaseTimer.Start(); // start renewing lease
                }
            }
            catch (StorageException ex)
            {
                if (ex.Message.Contains("(409) Conflict")) // lost lease
                {
                    leaseTimer.Stop(); // lost lease, stop renewing
                    this.gatekeeperAccess = null;
                }
            }

            return this.gatekeeperAccess != null;
        }

        public void Stop()
        {
            leaseTimer.Stop();
            // release gatekeeper lease
            gateBlob.ReleaseLease(this.gatekeeperAccess);

        }

        public string GetText()
        {
            return gateBlob.DownloadText(null, gatekeeperAccess);
        }

        public void SetText(string text)
        {
            gateBlob.UploadText(text, null, gatekeeperAccess);
        }

        //NOTE: this is the "cheap" way of seeing if we have a lease. It assumes
        // we haven't lost the lease since our last attempt to renew it. 
        // If we want to ensure we haven't lost it, we should renew it again
        public bool HasLease(bool aquireIfNoLease = true)
        {
            if ((gatekeeperAccess == null) && (aquireIfNoLease))
                this.Start();

            return (gatekeeperAccess != null);
        }

        private void RenewLeaseEvent(Object source, ElapsedEventArgs e)
        {
            try
            {
                gateBlob.RenewLease(this.gatekeeperAccess);
            }
            catch (StorageException ex)
            {
                if (ex.Message.Contains("(409) Conflict")) // lost lease
                {
                    leaseTimer.Stop(); // lost lease, stop renewing
                    this.gatekeeperAccess = null;
                }
            }
        }

    }
}
